package org.example.springextension.controller;

import jakarta.annotation.Resource;
import org.example.springextension.constants.Constants;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Date;

@RequestMapping("/producer")
@RestController
public class ProducerController {
    @Resource(name = "rabbitTemplate")
    private RabbitTemplate rabbitTemplate;
    @Resource(name = "confirmRabbitTemplate")
    private RabbitTemplate confirmRabbitTemplate;
    @Resource(name = "transRabbitTemplate")
    private  RabbitTemplate transRabbitTemplate;
    @RequestMapping("/ack")
    public String ack() {
        rabbitTemplate.convertAndSend(Constants.ACK_EXCHANGE, "ack","consumer ack mode test...");
        System.out.println("消息发送成功");
        return "消息发送成功";
    }
    @RequestMapping("/confirm")
    public String confirm() {
        //发送方确认机制是需要配置成手动确认的，yml文件也需要进行配置
        CorrelationData correlationData=new CorrelationData("1");
        confirmRabbitTemplate.convertAndSend(Constants.CONFIRM_EXCHANGE, "confirm","confirm test...",correlationData);
        System.out.println("发送消息成功");
        return "消息发送成功";
    }
    @RequestMapping("/returns")
    public String returns() {
        CorrelationData correlationData=new CorrelationData("5");
        confirmRabbitTemplate.convertAndSend(Constants.CONFIRM_EXCHANGE, "confirm","confirm test...",correlationData);
        System.out.println("发送消息成功");
        return "消息发送成功";
    }
    @RequestMapping("/retry")
    public String retry() {
        rabbitTemplate.convertAndSend(Constants.RETRY_EXCHANGE, "retry","retry test...");
        System.out.println("retry发送消息成功");
        return "消息发送成功";
    }
    @RequestMapping("/ttl")
    //当先发送过期时间大的话
    //就拿这个这个例子来说，一开始的话，是两个消息，按道理来说的话，应该过完10s的时候，消失一个消息
    //但是这个情况是过完20s的时候一起消失的。
    public String ttl() {
        rabbitTemplate.convertAndSend(Constants.TTL_EXCHANGE, "ttl2","ttl test...2",message ->{
            message.getMessageProperties().setExpiration("2000");
            return message;
        });
        rabbitTemplate.convertAndSend(Constants.TTL_EXCHANGE, "ttl2","ttl test...1",message ->{
            message.getMessageProperties().setExpiration("1000");
            return message;
        });
        System.out.println("ttl发送消息成功");
        return "消息发送成功";
    }
    @RequestMapping("/ttl2")
    public String ttl2() {
        //发送普通消息
        rabbitTemplate.convertAndSend(Constants.TTL_EXCHANGE, "ttl","ttl test...");
        System.out.println("ttl发送普通消息成功");
        return "消息发送成功";
    }
    @RequestMapping("/dl")
    public String dl() {
        System.out.println("dl...");
        //发送普通消息
        rabbitTemplate.convertAndSend(Constants.NORMAL_EXCHANGE, "normal", "dl test1...");
        rabbitTemplate.convertAndSend(Constants.NORMAL_EXCHANGE, "normal", "dl test2...",message -> {
            message.getMessageProperties().setExpiration("10000");
            return  message;
        });
        System.out.printf("%tc 消息发送成功 \n", new Date());
//        //测试队列长度
//        for (int i = 0; i < 20; i++) {
//            rabbitTemplate.convertAndSend(Constants.NORMAL_EXCHANGE, "normal", "dl test..."+i);
//        }
        return "消息发送成功";
    }
    //用ttl+死信队列来实现延迟队列
    //延迟队列是将消息迟点发送到这个队列，然后延迟时间到了，再进行消费这个消息
    //而ttl队列是将消息存储在队列中，如果消息到期了 ，就会自动消失
    @RequestMapping("/delay")
    public String delay() {
        System.out.println("delay...");

        rabbitTemplate.convertAndSend(Constants.NORMAL_EXCHANGE, "normal", "ttl test 10s...", message -> {
            message.getMessageProperties().setExpiration("30000");  //单位: 毫秒, 过期时间为10s
            return message;
        });

        rabbitTemplate.convertAndSend(Constants.NORMAL_EXCHANGE, "normal", "ttl test 30s...", message -> {
            message.getMessageProperties().setExpiration("10000");  //单位: 毫秒, 过期时间为30s
            return message;
        });

        System.out.printf("%tc 消息发送成功 \n", new Date());
        return "消息发送成功";
    }
    //而在这个插件的延迟队列下 ，我们在队列中应该是看不到消息的
    //消息直接发送到队列中的话 ，直接就被消费了
    //在这个延迟队列中消息的顺序是可以被保障的
    @RequestMapping("/delay2")
    public String delay2() {
        System.out.println("delay2...");

        rabbitTemplate.convertAndSend(Constants.DELAY_EXCHANGE, "delay", "delay test 10s...", message -> {
            message.getMessageProperties().setDelayLong(30000L);  //单位: 毫秒, 过期时间为10s
            return message;
        });

        rabbitTemplate.convertAndSend(Constants.DELAY_EXCHANGE, "delay", "delay test 30s...", message -> {
            message.getMessageProperties().setDelayLong(10000L);  //单位: 毫秒, 过期时间为30s
            return message;
        });

        System.out.printf("%tc 消息发送成功 \n", new Date());
        return "消息发送成功";
    }
    //先不开启事务的时候，只有一条消息被发送过去了
    //记得还要配置rabbitmq里面的配置
    //rabbitmq是基于amqp这个协议，这个协议有事务，所以rabbitmq也有事务这个机制
    @Transactional
    @RequestMapping("/trans")
    public String trans() {
        System.out.println("trans...");
        transRabbitTemplate.convertAndSend("","trans.queue","trans test1...");
        int sum=10/0;
        rabbitTemplate.convertAndSend("","trans.queue","trans test2...");
        return "消息发送成功";
    }

    //限流
    @RequestMapping("/qos")
    public String qos() {
        System.out.println("qos test...");
        for(int i =0;i<20;i++) {
            rabbitTemplate.convertAndSend(Constants.QOS_EXCHANGE, "qos","qos test1..."+i);
        }
        return "发送消息成功";
    }
}
